package org.yinxianren.java.test.thread;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 锁所提供的最重要的改进之一就是ReadWriteLock接口和唯一 一个实现它的ReentrantReadWriteLock类。这个类提供两把锁，
 * 一把用于读操作和一把用于写操作。同时可以有多个线程执行读操作，但只有一个线程可以执行写操作。
 * 当一个线程正在执行一个写操作，不可能有任何线程执行读操作。
 *
 * 在这个指南中，你将会学习如何使用ReadWriteLock接口实现一个程序，使用它来控制访问一个存储两个产品价格的对象。
 */
public class DemoReadWriteLock {
    public static void main(String[] args) {
        PricesInfo pricesInfo=new PricesInfo();

        Reader[] readers = new Reader[5];
        Thread[] threadsReader = new Thread[5];
        for (int i=0; i<5; i++){
            readers[i]=new Reader(pricesInfo);
            threadsReader[i]=new Thread(readers[i]);
        }
        Writer writer=new Writer(pricesInfo);
        Thread threadWriter=new Thread(writer);

        for (int i=0; i<5; i++){
            threadsReader[i].start();
        }
        threadWriter.start();

    }
}
/*
Thread-0: Price 1: 1.000000
Writer: Attempt to modify the prices.
Thread-4: Price 1: 1.000000
Thread-4: Price 2: 2.000000
Thread-4: Price 1: 1.000000
Thread-1: Price 1: 1.000000
Thread-1: Price 2: 6.680158
Thread-1: Price 1: 9.794370
Thread-1: Price 2: 6.680158
Thread-3: Price 1: 1.000000
Thread-3: Price 2: 6.680158
Thread-2: Price 1: 1.000000
Thread-3: Price 1: 9.794370
Thread-3: Price 2: 6.680158
Thread-1: Price 1: 9.794370
Thread-4: Price 2: 6.680158
Writer: Prices have been modified.
Thread-0: Price 2: 2.000000
Thread-4: Price 1: 9.794370
Thread-4: Price 2: 6.680158
Thread-1: Price 2: 6.680158
Thread-3: Price 1: 9.794370
Thread-2: Price 2: 6.680158
Thread-3: Price 2: 6.680158
Thread-3: Price 1: 9.794370
Thread-1: Price 1: 9.794370
Thread-4: Price 1: 9.794370
Thread-4: Price 2: 6.680158
Thread-4: Price 1: 9.794370
Thread-0: Price 1: 9.794370
Thread-4: Price 2: 6.680158
Writer: Attempt to modify the prices.
Thread-1: Price 2: 6.680158
Thread-1: Price 1: 4.003840
Thread-1: Price 2: 6.831568
Thread-3: Price 2: 6.680158
Thread-3: Price 1: 4.003840
Thread-3: Price 2: 6.831568
Thread-2: Price 1: 9.794370
Thread-3: Price 1: 4.003840
Thread-1: Price 1: 4.003840
Thread-1: Price 2: 6.831568
Thread-1: Price 1: 4.003840
Thread-1: Price 2: 6.831568
Thread-1: Price 1: 4.003840
Thread-1: Price 2: 6.831568
Writer: Prices have been modified.
Thread-4: Price 1: 9.794370
Thread-0: Price 2: 6.680158
Thread-4: Price 2: 6.831568
Thread-4: Price 1: 4.003840
Thread-4: Price 2: 6.831568
Thread-4: Price 1: 4.003840
Thread-1: Price 1: 4.003840
Thread-3: Price 2: 6.831568
Thread-2: Price 2: 6.831568
Thread-3: Price 1: 4.003840
Thread-1: Price 2: 6.831568
Thread-4: Price 2: 6.831568
Thread-4: Price 1: 4.003840
Thread-4: Price 2: 6.831568
Thread-0: Price 1: 4.003840
Thread-0: Price 2: 6.831568
Thread-4: Price 1: 4.003840
Thread-4: Price 2: 6.831568
Thread-1: Price 1: 4.003840
Thread-3: Price 2: 6.831568
Thread-2: Price 1: 4.003840
Thread-3: Price 1: 4.003840
Thread-3: Price 2: 6.831568
Thread-3: Price 1: 4.003840
Thread-3: Price 2: 6.831568
Thread-1: Price 2: 6.831568
Thread-0: Price 1: 4.003840
Thread-0: Price 2: 6.831568
Writer: Attempt to modify the prices.
Thread-0: Price 1: 4.003840
Thread-3: Price 1: 4.003840
Thread-3: Price 2: 4.052545
Thread-2: Price 2: 6.831568
Thread-0: Price 2: 4.052545
Writer: Prices have been modified.
Thread-0: Price 1: 2.014764
Thread-2: Price 1: 2.014764
Thread-0: Price 2: 4.052545
Thread-2: Price 2: 4.052545
Thread-2: Price 1: 2.014764
Thread-2: Price 2: 4.052545
Thread-2: Price 1: 2.014764
Thread-2: Price 2: 4.052545
Thread-2: Price 1: 2.014764
Thread-2: Price 2: 4.052545
Thread-2: Price 1: 2.014764
Thread-2: Price 2: 4.052545
Thread-2: Price 1: 2.014764
Thread-2: Price 2: 4.052545
Thread-2: Price 1: 2.014764
Thread-2: Price 2: 4.052545
Thread-0: Price 1: 2.014764
Thread-0: Price 2: 4.052545
Thread-0: Price 1: 2.014764
Thread-0: Price 2: 4.052545
Thread-0: Price 1: 2.014764
Thread-0: Price 2: 4.052545
Thread-0: Price 1: 2.014764
Thread-0: Price 2: 4.052545
 */
class PricesInfo {
    private double price1;
    private double price2;
    private ReadWriteLock lock;

    public PricesInfo(){
        price1=1.0;
        price2=2.0;
        lock=new ReentrantReadWriteLock();
    }

    public double getPrice1() {
        lock.readLock().lock();
        double value=price1;
        lock.readLock().unlock();
        return value;
    }

    public double getPrice2() {
        lock.readLock().lock();
        double value=price2;
        lock.readLock().unlock();
        return value;
    }

    public void setPrices(double price1, double price2) {
        lock.writeLock().lock();
        this.price1=price1;
        this.price2=price2;
        try {
            TimeUnit.SECONDS.sleep(5);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        lock.writeLock().unlock();
    }

}

class Reader implements Runnable {
    private PricesInfo pricesInfo;
    public Reader (PricesInfo pricesInfo){
        this.pricesInfo=pricesInfo;
    }

    @Override
    public void run() {
        for (int i=0; i<10; i++){
            System.out.printf("%s: Price 1: %f\n", Thread.currentThread().getName(),pricesInfo.getPrice1());
            System.out.printf("%s: Price 2: %f\n", Thread.currentThread().getName(),pricesInfo.getPrice2());
        }
    }
}

class Writer implements Runnable {

    private PricesInfo pricesInfo;
    public Writer(PricesInfo pricesInfo){
        this.pricesInfo=pricesInfo;
    }


    @Override
    public void run() {
        for (int i=0; i<3; i++) {
            System.out.printf("Writer: Attempt to modify the prices.\n");
            pricesInfo.setPrices(Math.random()*10, Math.random()*8);
            System.out.printf("Writer: Prices have been modified.\n");
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}